VHDL 和 Verilog 生成
从 SpinalHDL 组件生成 VHDL 和 Verilog
要从 SpinalHDL 组件生成 VHDL,您只需在 Scala main 函数中调用 SpinalVhdl(new YourComponent) 即可。
生成 Verilog 完全相同,但用 SpinalVerilog 代替 SpinalVHDL
import spinal.core._
// A simple component definition.
class MyTopLevel extends Component {
  // Define some input/output signals. Bundle like a VHDL record or a Verilog struct.
  val io = new Bundle {
    val a = in  Bool()
    val b = in  Bool()
    val c = out Bool()
  }
  // Define some asynchronous logic.
  io.c := io.a & io.b
}
// This is the main function that generates the VHDL and the Verilog corresponding to MyTopLevel.
object MyMain {
  def main(args: Array[String]) {
    SpinalVhdl(new MyTopLevel)
    SpinalVerilog(new MyTopLevel)
  }
}
重要
SpinalVhdl 和 SpinalVerilog 可能需要创建组件类的多个实例,因此第一个参数不是 Component 引用,而是返回新组件的函数。
重要
SpinalVerilog 实施于 2016 年 6 月 5 日开始。该后端成功通过了与 VHDL 相同的回归测试(RISCV CPU、多核和流水线 Mandelbrot、UART RX/TX、单时钟域 fifo、双时钟域 fifo、格雷码计数器, …)。
如果您对这个新后端有任何问题,请创建 Github 工单 描述问题。
Scala 的参数化
| 参数名称 | 类型 | 默认值 | 描述 | 
|---|---|---|---|
| 
 | SpinalMode | null | 设置 SpinalHDL 生成HDL的模式。 可以设置为  VHDL或Verilog | 
| 
 | ClockDomainConfig | RisingEdgeClock AsynchronousReset ResetActiveHigh ClockEnableActiveHigh | 设置将用作所有新 ``ClockDomain``时钟域默认值的配置。 | 
| 
 | Boolean | false | 将所有无符号/有符号顶级 io 更改为 std_logic_vector类型。 | 
| 
 | IClockDomainFrequency | UnknownFrequency | 默认时钟频率。 | 
| 
 | String | 当前目录 | 生成文件的目录。 | 
| 
 | Boolean | false | Instead of generating one big VHDL/Verilog file, every component will get its own VHDL/Verilog file. | 
| 
 | String | ToplevelClassName.(vhd|v) | Allow to change the name of the generated VHDL/Verilog. | 
| 
 | String | “” | Will add the given prefix in the front of every global symboles in the VHDL/Verilog (components/modules/enums). This allows to avoid naming conflict between multiple generated file. | 
| 
 | Boolean | false | Every generated Component/Modules names will get prefixed with the toplevel Component/Module name (excepted for the toplevel). This allows to avoid naming conflict between multiple generated file. | 
| 
 | Boolean | false | Enable the generation of the formal assertions in the VHDL/Verilog. | 
| 
 | String | “zz_” | Set the prefix added to unnamed signals. | 
| 
 | Boolean | false | Configure the Verilog backend to incorporate the ROM values initialization in the verilog itself instead of an bin file. | 
| 
 | Boolean | false | Generate the ROM as a big switch case. | 
| 
 | Boolean | false | Will merge process/always blocks for combinatorial signal which share at least one conditional assignement (if/switch statment) | 
| 
 | Boolean | true | Will merge process/always blocks for flip-flops which use the same clock domain (if/switch statment) | 
| 
 | Boolean | false | For each hardware assignment in the generated VHDL/Verilog code, will attach a comment which specifies in which scala file, at which line, the assignement happend. Ex : a = 1’b1; // @ MyDesign.scala l1135 | 
| 
 | Boolean | false | Remove all the asserts from the generated code | 
| 
 | Boolean | false | Add the date at which the VHDL/Verilog was generated in its header. | 
| 
 | Boolean | true | Add the current directory git hash in the generated VHDL/Verilog header. | 
| 
 | Boolean | false | Replace mySignal.assignDontCare() by mySignal := 0 | 
| 
 | Boolean | false | Will obfuscate the generated components and signal names. | 
| 
 | String | disabled | Allow to manualy specify the VHDL/Verilog file header | 
| 
 | Boolean | True | Enable the addition of the timescale in the generated Verilog | 
这是设置它们的语法:
SpinalConfig(mode=VHDL, targetDirectory="temp/myDesign").generate(new UartCtrl)
// Or for Verilog in a more scalable formatting:
SpinalConfig(
  mode=Verilog,
  targetDirectory="temp/myDesign"
).generate(new UartCtrl)
来自 shell 的参数化
您还可以使用命令行参数指定生成参数。
def main(args: Array[String]): Unit = {
  SpinalConfig.shell(args)(new UartCtrl)
}
命令行参数的语法是:
Usage: SpinalCore [options]
  --vhdl
        Select the VHDL mode
  --verilog
        Select the Verilog mode
  -d | --debug
        Enter in debug mode directly
  -o <value> | --targetDirectory <value>
        Set the target directory
生成的 VHDL 和 Verilog
如何将 SpinalHDL RTL 描述转换为 VHDL 和 Verilog 非常重要:
- Scala 中变量的名称将保留在 VHDL 和 Verilog 中。 
- Scala 中的 - Component组件层次结构会保留在 VHDL 和 Verilog 中。
- Scala 中的 - when语句会生成为 VHDL 和 Verilog 中的 if 语句。
- Scala 中的 - switch语句在所有标准情况下都生成为 VHDL 和 Verilog 中的 case 语句。
组织
当您使用 VHDL 生成器时,所有模块都会生成到一个文件中,其中包含三个部分:
- 包含所有 Enum 定义的包 
- 包含架构中所有元素使用函数的包 
- 您的设计所需的所有组件 
当您使用 Verilog 生成时,所有模块都会生成到一个文件中,其中包含两个部分:
- 使用的所有枚举定义 
- 您的设计需要的所有模块 
组合逻辑
Scala:
class TopLevel extends Component {
  val io = new Bundle {
    val cond           = in  Bool()
    val value          = in  UInt(4 bits)
    val withoutProcess = out UInt(4 bits)
    val withProcess    = out UInt(4 bits)
  }
  io.withoutProcess := io.value
  io.withProcess := 0
  when(io.cond) {
    switch(io.value) {
      is(U"0000") {
        io.withProcess := 8
      }
      is(U"0001") {
        io.withProcess := 9
      }
      default {
        io.withProcess := io.value+1
      }
    }
  }
}
VHDL:
entity TopLevel is
  port(
    io_cond : in std_logic;
    io_value : in unsigned(3 downto 0);
    io_withoutProcess : out unsigned(3 downto 0);
    io_withProcess : out unsigned(3 downto 0)
  );
end TopLevel;
architecture arch of TopLevel is
begin
  io_withoutProcess <= io_value;
  process(io_cond,io_value)
  begin
    io_withProcess <= pkg_unsigned("0000");
    if io_cond = '1' then
      case io_value is
        when pkg_unsigned("0000") =>
          io_withProcess <= pkg_unsigned("1000");
        when pkg_unsigned("0001") =>
          io_withProcess <= pkg_unsigned("1001");
        when others =>
          io_withProcess <= (io_value + pkg_unsigned("0001"));
      end case;
    end if;
  end process;
end arch;
时序逻辑
Scala:
class TopLevel extends Component {
  val io = new Bundle {
    val cond   = in Bool()
    val value  = in UInt (4 bits)
    val resultA = out UInt(4 bits)
    val resultB = out UInt(4 bits)
  }
  val regWithReset = Reg(UInt(4 bits)) init(0)
  val regWithoutReset = Reg(UInt(4 bits))
  regWithReset := io.value
  regWithoutReset := 0
  when(io.cond) {
    regWithoutReset := io.value
  }
  io.resultA := regWithReset
  io.resultB := regWithoutReset
}
VHDL:
entity TopLevel is
  port(
    io_cond : in std_logic;
    io_value : in unsigned(3 downto 0);
    io_resultA : out unsigned(3 downto 0);
    io_resultB : out unsigned(3 downto 0);
    clk : in std_logic;
    reset : in std_logic
  );
end TopLevel;
architecture arch of TopLevel is
  signal regWithReset : unsigned(3 downto 0);
  signal regWithoutReset : unsigned(3 downto 0);
begin
  io_resultA <= regWithReset;
  io_resultB <= regWithoutReset;
  process(clk,reset)
  begin
    if reset = '1' then
      regWithReset <= pkg_unsigned("0000");
    elsif rising_edge(clk) then
      regWithReset <= io_value;
    end if;
  end process;
  process(clk)
  begin
    if rising_edge(clk) then
      regWithoutReset <= pkg_unsigned("0000");
      if io_cond = '1' then
        regWithoutReset <= io_value;
      end if;
    end if;
  end process;
end arch;
VHDL 和 Verilog 属性
在某些情况下,为设计中的某些信号提供属性以修改它们的综合方式很有用。
为此,您可以对设计中的任何信号或存储器调用以下函数:
| 语法 | 描述 | 
|---|---|
| 
 | 添加一个名为  | 
| 
 | 添加一个字符串属性,并将给定的  | 
示例:
val pcPlus4 = pc + 4
pcPlus4.addAttribute("keep")
用 VHDL 生成声明:
attribute keep : boolean;
signal pcPlus4 : unsigned(31 downto 0);
attribute keep of pcPlus4: signal is true;
用 Verilog 生成声明:
(* keep *) wire [31:0] pcPlus4;